//
//  PMPolygonShape.m
//  PezMonkey
//
//  Created by Spence DiNicolantonio on 10/29/09.
//  Copyright 2009 Necrosoft. All rights reserved.
//

/**
 * A subclass of PMShape for representing convex polygon collision shapes. The 
 * PMPolygonShape must be defined with clockwise winding.
 */

#import "PMPolygonShape.h"
#import "PMBody.h"


@implementation PMPolygonShape


#pragma mark -
#pragma mark Init

/**
 * Returns a PMPolygonShape object initialized to correspond to a given PMBody 
 * object, constructed using a given set of vertices relative to the body's center
 * of gravity. The given vertices must define a convex polygon with clockwise 
 * winding. An assertion will be thrown if this is not the case.
 */
- (id)initWithBody:(PMBody *)aBody vertices:(PMVect[])vertices vertCount:(NSUInteger)vertCount {
	return [self initWithBody:aBody 
					 vertices:vertices
				  vertCount:vertCount
					   center:PMVectZero];
}

/**
 * Returns a PMPolygonShape object initialized to correspond to a given PMBody 
 * object, constructed using a given set of vertices relative to a given center
 * point offset from the body's center of gravity. The given vertices must define 
 * a convex polygon with clockwise winding. An exception will be thrown if this 
 * is not the case.
 */
- (id)initWithBody:(PMBody *)aBody vertices:(PMVect[])vertices vertCount:(NSUInteger)vertCount center:(PMVect)center {
	// validate vertices
	if (![PMPolygonShape validateVertices:vertices vertCount:vertCount])
		[NSException raise:@"Invalid Polygon" 
					format:@"Given vertices do not describe a convex polygon with clockwise winding"];
	
	// allocate and initialize cpShape
	shape = cpPolyShapeNew(aBody.cpBody, vertCount, vertices, center);
	self.body = aBody;
	
	// reference this PMShape object with cpShape's data pointer
	// this is for internal use
	shape->data = self;
	
	return self;
}


#pragma mark Convenience

/**
 * Creates and returns a PMPolygonShape object initialized to correspond to a given 
 * PMBody object, constructed using a given set of vertices relative to the body's 
 * center of gravity. The given vertices must define a convex polygon with clockwise 
 * winding. An exception will be thrown if this is not the case.
 */
+ (PMPolygonShape *)polygonShapeWithBody:(PMBody *)aBody vertices:(PMVect[])vertices vertCount:(NSUInteger)vertCount {
	return [[[PMPolygonShape alloc] initWithBody:aBody 
										vertices:vertices
									 vertCount:vertCount] autorelease];
}

/**
 * Creates and returns a PMPolygonShape object initialized to correspond to a given 
 * PMBody object, constructed using a given set of vertices relative to a given 
 * center point offset from the body's center of gravity. The given vertices must 
 * define a convex polygon with clockwise winding. An exception will be thrown if 
 * this is not the case.
 */
+ (PMPolygonShape *)polygonShapeWithBody:(PMBody *)aBody vertices:(PMVect[])vertices vertCount:(NSUInteger)vertCount center:(PMVect)center {
	return [[[PMPolygonShape alloc] initWithBody:aBody
										vertices:vertices
									 vertCount:vertCount
										  center:center] autorelease];
}



#pragma mark -
#pragma mark Getters

/**
 * Returns the number of vertices that make up the receiver.
 */
- (NSUInteger)vertCount {
	return ((cpPolyShape *) shape)->numVerts;
}

/**
 * Returns a pointer to an array of the receiver's vertices. These vertices should
 * never be altered in any way. This method should be used for reference only.
 */
- (PMVect *)vertices {
	return (PMVect *) ((cpPolyShape *) shape)->verts;
}

/**
 * Returns the receiver's vertex located at a given index. For example, if the
 * receiver is a square (four vertices) passing an index value 2 will give return
 * the 3rd vertex originally given in the receiver's construction.
 */
- (PMVect)vertexAtIndex:(NSInteger)index {
	return (PMVect) ((cpPolyShape *) shape)->verts[index];
}


#pragma mark -
#pragma mark Setters

/**
 * Sets the vertices that define the receiver to a given set of vertices, relative
 * to a given center point offset from the receiver's corresponding PMBody's center 
 * of gravity. The given vertices must define a convex polygon with clockwise winding. 
 * An exception will be thrown if this is not the case.
 */
- (void)setVertices:(PMVect[])vertices vertCount:(NSUInteger)vertCount center:(PMVect)center {
	// validate vertices
	if (![PMPolygonShape validateVertices:vertices vertCount:vertCount])
		[NSException raise:@"Invalid Polygon" 
					format:@"Given vertices do not describe a convex polygon with clockwise winding"];
	
	// set vertices
	cpPolyShapeSetVerts(shape, vertCount, vertices, center);
}

/**
 * Sets the vertices that define the receiver to a given set of vertices. The 
 * given vertices must define a convex polygon with clockwise winding. An exception 
 * will be thrown if this is not the case.
 */
- (void)setVertices:(PMVect[])vertices vertCount:(NSUInteger)vertCount {
	[self setVertices:vertices 
			vertCount:vertCount 
			   center:PMVectZero];
}


#pragma mark -
#pragma mark Other Methods

/**
 * Determines whether a given set of vertices describes a valid convex polygon
 * with clockwise winding.
 */
+ (BOOL)validateVertices:(PMVect[])vertices vertCount:(NSUInteger)vertCount {
	return cpPolyValidate(vertices, vertCount);
}


@end
